/* 
 * To change this license header, choose License Headers in Project Properties.
 * To change this template file, choose Tools | Templates
 * and open the template in the editor.
 */

SOAPClient_cacheWsdl = new Array(); // private: wsdl cache

function SOAPClientParameters()
{
    var params = new Array();
    this.add = function(name, value)
    {
        params[name] = value;
        return this;
    };
    this.gettype = function()
    {
        return params["typedata"];
    };
    this.toXml = function()
    {
        var xml = "";
        for (var p in params)
        {
            if (p !== "typedata")
            {
                switch (typeof (params[p]))
                {
                    case "string":
                    case "number":
                    case "boolean":
                    case "object":
                        if (p !== undefined)
                            xml += "<" + p + ">" + SOAPClientParameters.serialize(params[p]) + "</" + p + ">";
                        break;
                    default:
                        break;
                }
            }
        }
        return xml;
    };
}

SOAPClientParameters.serialize = function(o)
{
    var s = "";
    switch (typeof (o))
    {
        case "string":
            s += o.replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;");
            break;
        case "number":
        case "boolean":
            s += o.toString();
            break;
        case "object":
            // Date
            if (o.constructor.toString().indexOf("function Date()") > -1)
            {
                var year = o.getFullYear().toString();
                var month = (o.getMonth() + 1).toString();
                month = (month.length == 1) ? "0" + month : month;
                var date = o.getDate().toString();
                date = (date.length == 1) ? "0" + date : date;
                var hours = o.getHours().toString();
                hours = (hours.length == 1) ? "0" + hours : hours;
                var minutes = o.getMinutes().toString();
                minutes = (minutes.length == 1) ? "0" + minutes : minutes;
                var seconds = o.getSeconds().toString();
                seconds = (seconds.length == 1) ? "0" + seconds : seconds;
                var milliseconds = o.getMilliseconds().toString();
                var tzminutes = Math.abs(o.getTimezoneOffset());
                var tzhours = 0;
                while (tzminutes >= 60)
                {
                    tzhours++;
                    tzminutes -= 60;
                }
                tzminutes = (tzminutes.toString().length == 1) ? "0" + tzminutes.toString() : tzminutes.toString();
                tzhours = (tzhours.toString().length == 1) ? "0" + tzhours.toString() : tzhours.toString();
                var timezone = ((o.getTimezoneOffset() < 0) ? "+" : "-") + tzhours + ":" + tzminutes;
                s += year + "-" + month + "-" + date + "T" + hours + ":" + minutes + ":" + seconds + "." + milliseconds + timezone;
            }
            // Array
            else if (o.constructor.toString().indexOf("function Array()") > -1)
            {
                for (var p in o)
                {
                    if (!isNaN(p))   // linear array
                    {
                        (/function\s+(\w*)\s*\(/ig).exec(o[p].constructor.toString());
                        var type = RegExp.$1;
                        switch (type)
                        {
                            case "":
                                type = typeof (o[p]);
                            case "String":
                                type = "string";
                                break;
                            case "Number":
                                type = "int";
                                break;
                            case "Boolean":
                                type = "bool";
                                break;
                            case "Date":
                                type = "DateTime";
                                break;
                        }
                        s += "<" + type + ">" + SOAPClientParameters.serialize(o[p]) + "</" + type + ">"
                    }
                    else    // associative array
                        s += "<" + p + ">" + SOAPClientParameters.serialize(o[p]) + "</" + p + ">"
                }
            }
            // Object or custom function
            else
                for (var p in o)
                    s += "<" + p + ">" + SOAPClientParameters.serialize(o[p]) + "</" + p + ">";
            break;
        default:
            break;
    }
    return s;
};

function SOAPClient() {
}

SOAPClient.invoke = function (url, proc, parameters, async, func_callback) {
    SOAPClient.loadWSDL(url, proc, parameters, func_callback);
};

SOAPClient.loadWSDL = function (url, proc, parameters, func_callback) {
    SOAPClient.sendRequest(url + "?wsdl", "GET", parameters, SOAPClient.loadWSDL_complete, proc, func_callback, null, null);
};

SOAPClient.loadWSDL_complete = function(url, parameters, proc, func_callback, data) {
    var wsdl = data;
    url = url.replace("?wsdl", "");
    SOAPClient_cacheWsdl[url] = wsdl;	// save a copy in cache
    SOAPClient.sendSoapRequest(url, parameters, proc, func_callback, wsdl);
};

SOAPClient.getXMLHttpRequest  =  function () {
    if (window.XMLHttpRequest) {
        return new window.XMLHttpRequest;
    } else {
        try {
            return new ActiveXObject("MSXML2.XMLHTTP");
        } catch (ex) {
            return null;
        }
    }
};

SOAPClient.sendSoapRequest = function (url, parameters, proc, func_callback, wsdl) {
    // get namespace
    var xmlDoc = parseXml(wsdl);
    var ns = (xmlDoc.documentElement.attributes["targetNamespace"] + "" === "undefined") ? xmlDoc.documentElement.attributes.getNamedItem("targetNamespace").nodeValue : xmlDoc.documentElement.attributes["targetNamespace"].value;
    // build SOAP request
    var request_payload = "";
    if (parameters.gettype() !== undefined)
        request_payload =
                '<soapenv:Envelope xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/">' +
                '<soapenv:Header/>' +
                '<soapenv:Body>' +
                '<' + proc + ' soapenv:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/">' +
                '<' + parameters.gettype() + ' xsi:type="m:' + parameters.gettype() + '" xmlns:m="http://localhost/soap//buzzPulse/m/">' +
                parameters.toXml() +
                '</' + parameters.gettype() + '>' +
                '</' + proc + '>' +
                '</soapenv:Body>' +
                '</soapenv:Envelope>';
    else
        request_payload =
                '<soapenv:Envelope xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/">' +
                '<soapenv:Header/>' +
                '<soapenv:Body>' +
                '<' + proc + ' soapenv:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/">' +
                parameters.toXml() +
                '</' + proc + '>' +
                '</soapenv:Body>' +
                '</soapenv:Envelope>';
    var xmlHttp = SOAPClient.getXMLHttpRequest();
    var soapaction = ((ns.lastIndexOf("/") !== ns.length - 1) ? ns + "/" : ns) + proc;
    curRequests.push(xmlHttp);
    xmlHttp.open("POST", url, true);
    xmlHttp.setRequestHeader("SOAPAction", soapaction);
    xmlHttp.setRequestHeader("Content-Type", "text/xml; charset=utf-8");
    SOAPClient.sendRequest(url, "POST", parameters, SOAPClient.sendSoapRequest_response, proc, func_callback, xmlHttp, request_payload);
};

SOAPClient.sendSoapRequest_response = function (url, parameters, proc, func_callback, data) {
    var xmlDoc = parseXml(data + "e>");
    var result;
    if(xmlDoc.documentElement.getElementsByTagName('return')[0].attributes["xsi:type"] !== undefined) {
        var type = xmlDoc.documentElement.getElementsByTagName('return')[0].attributes["xsi:type"].value;
    } else {
        var type = "NULL";
    }
    switch(type) {
        case "SOAP-ENC:Struct":
            var children = xmlDoc.documentElement.getElementsByTagName('return')[0].children;
            result = {};
            for(var key in children) {
                result[children[key].tagName] = children[key].textContent;
            }
            break;
        case "NULL":
            result = null;
            break;
        default:
            result = xmlDoc.documentElement.getElementsByTagName('return')[0].textContent;
            break;
    }
    func_callback(result);
};

SOAPClient.sendRequest = function (url, method, parameters, callback, proc, func_callback, xmlHttp, request_payload) {
    function getXMLHttpRequest() {
        if (window.XMLHttpRequest) {
            return new window.XMLHttpRequest;
        } else {
            try {
                return new ActiveXObject("MSXML2.XMLHTTP");
            } catch (ex) {
                return null;
            }
        }
    }
    
    if(xmlHttp === null) {
        var oReq = getXMLHttpRequest();
    } else {
        var oReq = xmlHttp;
    }
    
    function handler() {
        if (oReq.readyState === 4 /* complete */) {
            if (oReq.status === 200) {
                callback(url, parameters, proc, func_callback, oReq.responseText);
            }
        }
    }

    if (oReq !== null) {
        oReq.open(method, url, true);
        oReq.onreadystatechange = handler;
        oReq.onprogress = progress;
        oReq.send(request_payload);
        return oReq;
    } else {
        window.alert("AJAX (XMLHTTP) not supported.");
    }

    function progress() {

    }
};

var parseXml;

if (window.DOMParser) {
    parseXml = function(xmlStr) {
        return ( new window.DOMParser() ).parseFromString(xmlStr, "text/xml");
    };
} else if (typeof window.ActiveXObject !== "undefined" && new window.ActiveXObject("Microsoft.XMLDOM")) {
    parseXml = function(xmlStr) {
        var xmlDoc = new window.ActiveXObject("Microsoft.XMLDOM");
        xmlDoc.async = "false";
        xmlDoc.loadXML(xmlStr);
        return xmlDoc;
    };
} else {
    parseXml = function() { return null; };
}
